package driver

import (
	"encoding/csv"
	"fmt"
	"happy-sudoku/internal/model"
	"io"
	"strings"

	"github.com/jinzhu/gorm"
)

// IPuzzleGen to be implemented by PuzzleGen
type IPuzzleGen interface {
	ClearDB() error
	InsertToDB(input PuzzleInput) error
	GenerateFromCsv(reader io.Reader) error
}

// PuzzleGenCfg use to init PuzzleGen
type PuzzleGenCfg struct {
	DB *gorm.DB
}

// PuzzleGen generates puzzle, and insert to databse
type PuzzleGen struct {
	db *gorm.DB
}

// PuzzleInput use to input puzzle
type PuzzleInput struct {
	Content    string
	Difficulty model.Difficulty
}

// NewPuzzleGen new PuzzleGen
func NewPuzzleGen(cfg PuzzleGenCfg) *PuzzleGen {
	cfg.DB.AutoMigrate(&model.Puzzle{})

	return &PuzzleGen{
		db: cfg.DB,
	}
}

// ClearDB clear all puzzles in db
func (p *PuzzleGen) ClearDB() error {
	return p.db.DropTable(&model.Puzzle{}).AutoMigrate(&model.Puzzle{}).Error
}

// InsertToDB insert to db
func (p *PuzzleGen) InsertToDB(input PuzzleInput) error {
	res := p.db.Create(&model.Puzzle{
		ID:           0,
		Content:      input.Content,
		Difficulty:   input.Difficulty,
		PlayerPlayed: 0,
		HighestScore: 0,
		ShortestTime: 0,
	})
	return res.Error
}

// GenerateFromCsv generate puzzle from csv file
func (p *PuzzleGen) GenerateFromCsv(reader io.Reader) error {
	r := csv.NewReader(reader)

	err := p.ClearDB()
	if err != nil {
		return err
	}

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		if len(record) != 2 {
			return fmt.Errorf("Invalid record: %s", strings.Join(record, " "))
		}

		if record[0] == "Puzzle" {
			// the header, ignore
			continue
		}

		difficulty := model.Difficulty(record[1])
		if !difficulty.IsValid() {
			return fmt.Errorf("Invalid difficulty: %s", record[1])
		}

		p.InsertToDB(PuzzleInput{
			Content:    record[0],
			Difficulty: difficulty,
		})
	}
	fmt.Println("Puzzle Generate Successfully")
	return nil
}
